﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using DesignerHelper.Addons;
using DesignerHelper.Help;
using DesignerHelper.Main;
using SpreadsheetGear;

namespace WorkbookDesigner.Addons.DefineName
{
    public partial class DefineNameView : UserControl/*, IMarine<IWorksheet>, IMarine<IWorkbook>*/
    {
        /// <summary>
        /// 获取listview控件中选中项的索引
        /// </summary>
        private ListView.SelectedIndexCollection SelectedIndices => listViewNames.SelectedIndices;

        private List<IName> AllNames { get; set; }
        private bool DrawMyself
        {
            get { return listViewNames.OwnerDraw; }
            set { listViewNames.OwnerDraw = value; }
        }

        private bool IsInSearchMode => !string.IsNullOrEmpty(SearchText);
        private ListViewItem LastSelectedItem { get; set; }
        private LockBookWorker LbwTrigger { get; } = new LockBookWorker();
        private string RefersToText
        {
            get
            {
                return textBoxRefersTo.Text;
            }
            set
            {
                textBoxRefersTo.Text = value;
            }
        }

        private string FormulaOfName
        {
            get { return textBoxValue.Text; }
            set { textBoxValue.Text = value; }
        }
        private List<IName> SearchNames { get; set; }

        private string SearchText => textBoxSearch.Text;
        private IWorkbook SelectedBook { get; set; }
        /// <summary>
        /// 获取listview控件中的选中项
        /// </summary>
        private ListViewItem SelectedItem { get; set; }

        private IWorksheet SelectedSheet { get; set; }
        private IWorkbookSet WorkbookSet { get; set; }
        private List<IName> WorkingList => IsInSearchMode ? SearchNames : AllNames;
        private OperationType WorkMode { get; set; }


        public bool InSearchMode => !string.IsNullOrEmpty(NameToSearch);

        public string NameToSearch => textBoxSearch.Text;

        #region  初始化函数

        public DefineNameView()
        {
            InitializeComponent();
            DrawMyself = false;
            columnHeaderNames.Width = listViewNames.Width;
        }

        public DefineNameView(IWorkbook workbook) : this()
        {
            TriggerInit(workbook);
        }

        public DefineNameView(IWorksheet worksheet) : this()
        {
            TriggerInit(worksheet);
        }
        #endregion

        #region Trigger

        public void TriggerInit(IWorkbook workbook)
        {
            WorkMode = OperationType.Workbook;
            SelectedBook = workbook;
            WorkbookSet = SelectedBook.WorkbookSet;
            LbwTrigger.GetBookSet(WorkbookSet);
            TriggerReset();
        }

        public void TriggerInit(IWorksheet worksheet)
        {
            WorkMode = OperationType.Worksheet;

            SelectedSheet = worksheet;
            SelectedBook = SelectedSheet.Workbook;
            WorkbookSet = SelectedSheet.WorkbookSet;
            LbwTrigger.GetBookSet(WorkbookSet);

            TriggerReset();
        }
        /// <summary>
        /// 以上次初始化的工作簿/工作表为数据源刷新控件
        /// </summary>
        public void TriggerReset()
        {
            LbwTrigger.DoWork(() =>
            {
                ClearValueAndRefersTo();
                RefreshList();
                textBoxSearch.Clear();
                InitNameRefersToAndValue();
            });
        }
        /// <summary>
        /// 设定当前选定名称对应的引用位置值
        /// </summary>
        public void TriggerSet()
        {
            ListViewItem item = SelectedItem;
            if (item == null) return;
            DialogResult makesure = UsedDialog.SaveCheckDialog("确定保存所做的更改?");
            switch (makesure)
            {
                case DialogResult.Yes:
                    LbwTrigger.DoWork(() =>
                    {
                        IName name = item.Tag as IName;
                        if (name == null) return;
                        string text = name.RefersTo;
                        if (RefersToText == text && !string.IsNullOrEmpty(text))
                        {
                            MesBox.InfoMessage("未对名称的引用值做任何修改!");
                            return;
                        }
                        SetNameRefersTo(name, RefersToText);
                        //SetNameString(name, item.Text);//ps 已有相应方法进行修改

                    });
                    break;

                case DialogResult.No:
                    InitNameRefersToAndValue(item);
                    break;

                case DialogResult.Cancel:
                    break;
            }
        }

        #endregion

        #region Name/Item/RefersTo/Value Get&Set

        private IName GetIName(ListViewItem selectedItem)
        {
            return selectedItem?.Tag as IName;//ps null item
        }
        /// <summary>
        /// 初始化引用位置/公式栏文本框,取选中Item对应名称的值
        /// </summary>
        /// <param name="selectedItem">在ListView控件中选中的Item</param>
        private void InitNameRefersToAndValue(ListViewItem selectedItem)
        {
            ClearValueAndRefersTo();
            IName name = GetIName(selectedItem);
            if (name == null)
                return;
            LbwTrigger.DoWork(() =>
            {
                RefersToText = name.RefersTo;
                if (name.RefersToRange != null)
                {
                    //FormulaOfName = name.RefersToRange.Value as string;//ps value还是formula?
                    FormulaOfName = name.RefersToRange.Formula;
                }
            });
        }

        /// <summary>
        /// 初始化引用位置/公式栏文本框数值,取对应索引位置为0的名称的值
        /// </summary>
        private void InitNameRefersToAndValue()
        {
            if (AllNames.Count == 0 || (IsInSearchMode && SearchNames.Count == 0))
                return;

            var item = listViewNames.FindItemWithText(IsInSearchMode ? SearchNames[0].Name : AllNames[0].Name);
            ClearSelectedIndices();
            AddSelectedIndices(item.Index);
            SelectedItem = item;
            item.EnsureVisible();
            InitNameRefersToAndValue(item);

        }


        private void InitNamesList(INames names)
        {
            listViewNames.Items.Clear();
            AllNames = names.Cast<IName>().ToList();
        }
        private void LocateRange(IName name)
        {
            IName n = name;
            LbwTrigger.DoWork(() =>
            {
                IRange range = n?.RefersToRange;
                range?.Select();
            });

        }

        /// <summary>
        /// 修正可能出现的选中项为空的情况，返回true表示成功,false表示无法修正
        /// </summary>
        private bool RefixSelectedItem()
        {
            if (listViewNames.FocusedItem == null && SelectedIndices.Count == 0)
                return false;
            SelectedItem = null;
            SelectedItem = listViewNames.FocusedItem;
            if (SelectedItem != null)
                AddSelectedIndices(SelectedItem.Index);

            return SelectedItem != null;

        }


        /// <summary>
        /// 设置选中的Item对应的名称的引用位置/公式值
        /// </summary>
        /// <param name="name">在ListView中选中的Item</param>
        /// <param name="newValue">将要设置的值</param>
        private void SetNameRefersTo(IName name, string newValue)
        {
            try
            {
                //todo 输入数据校验,非法字符报错
                name.RefersTo = newValue;
            }
            catch (ArgumentException ae)
            {
                MesBox.ErrorMessage(ae);
            }
        }

        /// <summary>
        /// 更改选定的Item对应的名称的值
        /// </summary>
        /// <param name="selectedItem">ListView中选中的Item</param>
        /// <param name="newName">设置的新名称</param>
        private void SetNameString(IName name, string newName)
        {
            try
            {
                name.Name = newName;
            }
            catch (ArgumentException ae)
            {
                MesBox.ErrorMessage(ae);
            }
        }
        #endregion

        #region 名称添加修改/右键菜单相关

        private void DeleteName()
        {
            if (!RefixSelectedItem())
            {
                MesBox.ErrorMessage("请先选中一个名称!");
                return;
            }
            ListView.SelectedIndexCollection indexCollection = SelectedIndices;
            Dictionary<IName, int> deleteDictionary = new Dictionary<IName, int>(indexCollection.Count);
            foreach (int index in indexCollection)
            {
                deleteDictionary.Add(WorkingList[index], index);
            }
            LbwTrigger.DoWork(() =>
            {
                int indexOffset = 0;
                foreach (var toDelete in deleteDictionary)
                {
                    IName nameToDelete = toDelete.Key;
                    int nameIndex = toDelete.Value - indexOffset;
                    indexCollection.Clear();
                    indexCollection.Add(nameIndex);
                    DialogResult makeSure = UsedDialog.DeleteCheckDialog("确定删除名称\"" + nameToDelete.Name + "\"？");
                    switch (makeSure)
                    {
                        case DialogResult.Yes:
                            {
                                indexCollection.Remove(nameIndex);
                                //WorkingList.Remove(nameToDelete);
                                nameToDelete.Delete();
                                indexOffset++;
                                break;
                            }
                    }
                    RefreshList();
                    //ResetListViewSize(WorkingList.Count);
                    if (RefixSelectedItem())
                        InitNameRefersToAndValue(SelectedItem);
                    else
                        ClearValueAndRefersTo();


                }
            });
        }

        private void EditName()
        {
            IName name = GetIName(SelectedItem);
            if (name == null) return;
            LbwTrigger.DoWork(() =>
            {
                using (DefineNameDialog newDia = new DefineNameDialog.NameEditor(name, SelectedBook))
                {
                    newDia.ShowDialog(this);
                }
            });
            listViewNames.RedrawItems(SelectedItem.Index, SelectedItem.Index, false);
        }

        private void NewDefineName()
        {
            switch (WorkMode)
            {
                case OperationType.Workbook:
                    using (DefineNameDialog inBook = new DefineNameDialog(SelectedBook, false, true))
                    {
                        inBook.ShowDialog();
                    }
                    break;
                case OperationType.Worksheet:
                    using (DefineNameDialog inSheet = new DefineNameDialog(SelectedSheet))
                    {
                        inSheet.ShowDialog();
                    }
                    break;
            }
            LbwTrigger.DoWork(RefreshList);
            if (RefixSelectedItem())
                InitNameRefersToAndValue(SelectedItem);

        }
        private void Rename(ListViewItem selectedItem, string newName)
        {
            if (SelectedItem == null)
            {
                MesBox.ErrorMessage("请选中一个名称");
                return;
            }
            LbwTrigger.DoWork(() =>
            {
                try
                {
                    IName nameToRename = GetIName(selectedItem);

                    if (nameToRename != null)
                        nameToRename.Name = newName;
                    else
                        MesBox.ErrorMessage("找不到对应的名称");
                }
                catch (ArgumentException)
                {
                    MesBox.ErrorMessage("输入的名称不符合规范!");
                }
            });
        }
        #endregion



        private int AddSelectedIndices(int index)
        {
            return SelectedIndices.Add(index);
        }

        private void ClearSelectedIndices()
        {
            SelectedIndices.Clear();
        }

        private void ClearValueAndRefersTo()
        {
            textBoxRefersTo.Clear();
            textBoxValue.Clear();
        }

        private void DefineNameView_Load(object sender, EventArgs e)
        {
            //RefreshNameListEventHandler += (x, y) => RefreshList();
        }

        private void ResetListViewSize(int size)
        {
            listViewNames.VirtualListSize = size;
        }
        private void textBoxSearch_TextChanged(object sender, EventArgs e)
        {
            LbwTrigger.DoWork(() =>
            {
                RefreshList();
                ClearValueAndRefersTo();
                InitNameRefersToAndValue();
            });


        }

        private static class UsedDialog
        {

            internal static DialogResult DeleteCheckDialog(string checkString)
            {
                return MessageBox.Show(checkString, About.MyName, MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1);
            }
            internal static DialogResult SaveCheckDialog(string checkString)
            {
                return MessageBox.Show(checkString, About.MyName, MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
            }
        }

        private static class UsedFont
        {
            internal static Font BoldFont { get; } = new Font("微软雅黑", 12F, FontStyle.Bold, GraphicsUnit.Pixel, 134);
            internal static Font RegularFont { get; } = new Font("微软雅黑", 12F, FontStyle.Regular, GraphicsUnit.Pixel, 134);

        }

        #region 刷新listview


        private void RefreshList()
        {
            switch (WorkMode)
            {
                case OperationType.Workbook:
                    InitNamesList(SelectedBook.Names);
                    break;
                case OperationType.Worksheet:
                    InitNamesList(SelectedSheet.Names);
                    break;
            }
            SearchNames = IsInSearchMode ?
                AllNames.Where(x => x.Name.ToUpper().Contains(SearchText.ToUpper())).ToList()
                : AllNames;
            ResetListViewSize(WorkingList.Count);
        }

        private class NameItem
        {
            internal IName Name { get; private set; }

            internal ListViewItem Item { get; private set; }
            internal string NameText { get; private set; }
            internal string RefersTo { get; private set; }
            internal string Formula { get; private set; }
            internal IRange Range { get; private set; }
            internal string Value { get; private set; }
            internal NameItem(IName name)
            {
                Name = name;
                Range = name.RefersToRange;
                RefersTo = name.RefersTo;
                NameText = name.Name;
                Formula = Range != null ? name.RefersToRange.Formula : string.Empty;
                Value = Range != null ? name.RefersToRange.Value as string : string.Empty;
                Item = new ListViewItem(Name.Name)
                {
                    Name = "ListViewItem" + Name.Name,
                    Font = UsedFont.RegularFont,
                    Tag = Name,
                };
            }
        }

        #endregion

        #region EventHandlers


        private void buttonEditName_Click(object sender, EventArgs e)
        {
            EditName();
        }

        private void buttonSaveChanges_Click(object sender, EventArgs e)
        {
            TriggerSet();
        }

        private void listViewNames_AfterLabelEdit(object sender, LabelEditEventArgs e)
        {
            //ps rename planA 
            //会出问题?
            e.CancelEdit = false;
            if (string.IsNullOrEmpty(e.Label))
            {
                if (e.Label != null)
                    MesBox.ErrorMessage("输入名称不能为空!");
                e.CancelEdit = true;
                listViewNames.LabelEdit = false;
                return;
            }
            Rename(listViewNames.Items[e.Item], e.Label);
            listViewNames.LabelEdit = false;
        }

        private void listViewNames_BeforeLabelEdit(object sender, LabelEditEventArgs e)
        {
            //Graphics g = listViewNames.CreateGraphics();

            //g.FillRectangle(Brushes.IndianRed, SelectedItem.Bounds);
            //g.DrawString("", SelectedItem.Font, Brushes.White, SelectedItem.Bounds);
        }

        private void listViewNames_CacheVirtualItems(object sender, CacheVirtualItemsEventArgs e)
        {
            //CacheItemList = new List<ListViewItem>(e.EndIndex - e.StartIndex + 1);
            //LbwTrigger.DoWork(() =>
            //{

            //});
        }

        private void listViewNames_DrawItem(object sender, DrawListViewItemEventArgs e)
        {
            //e.DrawBackground();
            ////e.DrawFocusRectangle();
            //e.Graphics.FillRectangle(Brushes.Transparent, e.Bounds);
            //e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
            //e.Graphics.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;

            //using (StringFormat strFmt = new StringFormat(StringFormatFlags.NoWrap))
            //{
            //    //e.Item.UseItemStyleForSubItems = true;
            //    //Font myFont = UsedFont.RegularFont;
            //    strFmt.Alignment = StringAlignment.Near; //文本垂直左对齐
            //    strFmt.LineAlignment = StringAlignment.Center; //文本水平居中
            //    LinearGradientBrush myBrush;
            //    if (SelectedItem != null && e.ItemIndex == SelectedItem.Index)
            //    {
            //        myBrush = new LinearGradientBrush(e.Bounds, Color.White, Color.IndianRed, LinearGradientMode.Horizontal);
            //        e.Graphics.FillRectangle(new LinearGradientBrush(e.Bounds, Color.IndianRed, Color.IndianRed, LinearGradientMode.Horizontal),
            //            e.Bounds);
            //        e.Graphics.DrawRectangle(Pens.Transparent, e.Bounds);
            //    }
            //    else
            //    {
            //        myBrush = new LinearGradientBrush(e.Bounds, e.Item.ForeColor, e.Item.ForeColor, LinearGradientMode.Horizontal);
            //        e.Graphics.FillRectangle(Brushes.Transparent, e.Bounds);
            //        e.Graphics.DrawRectangle(Pens.Transparent, e.Bounds);
            //    }
            //    if (listViewNames.LabelEdit && e.Item.Index == listViewNames.SelectedIndices[0])
            //        e.Graphics.DrawString("", e.Item.Font, myBrush, e.Bounds, strFmt);
            //    else
            //        e.Graphics.DrawString(e.Item.Text, e.Item.Font, myBrush, e.Bounds, strFmt);

            //}


        }

        private void listViewNames_DrawSubItem(object sender, DrawListViewSubItemEventArgs e)
        {
            //e.DrawBackground();
            //e.Graphics.FillRectangle(Brushes.Transparent, e.Item.Bounds);
            //e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
            //e.Graphics.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;

            //using (StringFormat strFmt = new StringFormat(StringFormatFlags.NoWrap))
            //{
            //    //e.Item.UseItemStyleForSubItems = true;
            //    //Font myFont = UsedFont.RegularFont;
            //    strFmt.Alignment = StringAlignment.Near; //文本垂直左对齐
            //    strFmt.LineAlignment = StringAlignment.Center; //文本水平居中
            //    SolidBrush myBrush;
            //    if (e.ItemIndex == SelectedItem.Index && SelectedItem != null)
            //    {
            //        myBrush = new SolidBrush(Color.White);
            //        e.Graphics.FillRectangle(Brushes.IndianRed, e.Item.Bounds);
            //        e.Graphics.DrawRectangle(Pens.IndianRed, e.Item.Bounds);
            //    }
            //    else
            //    {
            //        myBrush = new SolidBrush(e.Item.ForeColor);
            //        e.Graphics.FillRectangle(Brushes.Transparent, e.Item.Bounds);
            //        e.Graphics.DrawRectangle(Pens.Transparent, e.Item.Bounds);
            //    }
            //    if (listViewNames.LabelEdit && e.Item.Index == listViewNames.SelectedIndices[0])
            //        e.Graphics.DrawString("", e.Item.Font, myBrush, e.Bounds, strFmt);
            //    else
            //        e.Graphics.DrawString(e.Item.Text, e.Item.Font, myBrush, e.Bounds, strFmt);

            //}
        }

        private void listViewNames_ItemSelectionChanged(object sender, ListViewItemSelectionChangedEventArgs e)
        {
            SelectedItem = e.Item;

            if (LastSelectedItem != null && (listViewNames.FindItemWithText(LastSelectedItem.Text, false, 0) != null))
            {
                //重绘上一个item,默认触发retrieve事件获取相应item
                listViewNames.RedrawItems(LastSelectedItem.Index, LastSelectedItem.Index, false);
            }
            listViewNames.RedrawItems(e.Item.Index, e.Item.Index, false);//重绘当前item,触发retrieve事件
            InitNameRefersToAndValue(e.Item);
            //LocateRange(e.Item.Tag as IName);
            LastSelectedItem = SelectedItem;
        }
        private void listViewNames_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e)
        {

            LbwTrigger.DoWork(() =>
            {
                IName name = IsInSearchMode ? SearchNames[e.ItemIndex] : AllNames[e.ItemIndex];
                ListViewItem item = new ListViewItem(name.Name)
                {
                    Name = "ListViewItem" + name.Name,
                    Font = UsedFont.RegularFont,
                    Tag = name,
                };
                if (SelectedItem != null && e.ItemIndex == SelectedItem.Index)
                {
                    item.Font = UsedFont.BoldFont;
                }
                e.Item = item;
            });
        }

        private void listViewNames_SearchForVirtualItem(object sender, SearchForVirtualItemEventArgs e)
        {
            LbwTrigger.DoWork(() =>
            {
                e.Index = WorkingList.FindIndex(x => x.Name.Equals(e.Text));
            });
        }

        private void listViewNames_SelectedIndexChanged(object sender, EventArgs e)
        {
            //ListViewItem item = listViewNames.Items[SelectedIndices[SelectedIndices.Count - 1]];

        }

        private void ResetAll_Click(object sender, EventArgs e)
        {
            TriggerReset();//全部刷新,之前只刷新名称对应的数值
        }

        private void splitContainer1_SplitterMoved(object sender, SplitterEventArgs e)
        {
            columnHeaderNames.Width = listViewNames.Width;
        }
        private void toolStripMenuItemDelete_Click(object sender, EventArgs e)
        {
            DeleteName();
        }

        private void toolStripMenuItemNewName_Click(object sender, EventArgs e)
        {
            NewDefineName();
        }

        private void toolStripMenuItemRename_Click(object sender, EventArgs e)
        {
            //ps rename planB 
            //DefineNameDialog.NameEditor edit = new DefineNameDialog.NameEditor(GetIName(SelectedItem),SelectedBook);
            //edit.ShowDialog();
            if (SelectedItem != null)
            {
                listViewNames.LabelEdit = true;
                SelectedItem.BeginEdit();
                //listViewNames.RedrawItems(SelectedItem.Index, SelectedItem.Index, false);
            }
            else
            {
                MesBox.ErrorMessage("请先选中一个名称");
            }

        }

        //void INameListView.ResetListViewSize(int size)
        //{
        //    throw new NotImplementedException();
        //}

        public void AutoSizeColumn()
        {
            throw new NotImplementedException();
        }
        #endregion

        private void listViewNames_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Delete)
                DeleteName();
            if (e.Control && e.KeyCode == Keys.N)
                NewDefineName();
        }
    }

}

